package aceim.app.view.page.contactlist; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.Collections; import java.util.List; import aceim.api.dataentity.Buddy; import aceim.api.dataentity.BuddyGroup; import aceim.api.dataentity.MultiChatRoom; import aceim.api.service.ApiConstants; import aceim.api.utils.Logger; import aceim.app.Constants; import aceim.app.MainActivity; import aceim.app.R; import aceim.app.dataentity.Account; import aceim.app.dataentity.AccountOptionKeys; import aceim.app.dataentity.ProtocolResources; import aceim.app.utils.LinqRules.BuddyLinqRule; import aceim.app.utils.linq.KindaLinq; import aceim.app.utils.linq.KindaLinqRule; import android.content.SharedPreferences; import android.content.res.Resources; final class ContactListUpdater { private final byte mServiceId; private final ContactListAdapter mAdapter; private final ContactListModelGroup unreadGroup; private final ContactListModelGroup offlineGroup; private final ContactListModelGroup notInListGroup; private final ContactListModelGroup onlineGroup; private final ContactListModelGroup chatsGroup; private final ContactListModelGroup noGroup; private final List<ContactListModelGroup> mContactListGroups = Collections.synchronizedList(new ArrayList<ContactListModelGroup>()); private boolean showGroups = false; private boolean showOffline = true; private volatile boolean canStartRedraw = true; ContactListUpdater(byte serviceId, Resources resources, Class<? extends ContactListAdapter> adapterClass, ProtocolResources protocolResources) { this.mAdapter = initAdapter(adapterClass, protocolResources, mContactListGroups); this.mServiceId = serviceId; unreadGroup = initGroup(Constants.VIEWGROUP_UNREAD, resources.getString(R.string.unread_group), true); offlineGroup = initGroup(Constants.VIEWGROUP_OFFLINE, resources.getString(R.string.offline_group), true); notInListGroup = initGroup(Constants.VIEWGROUP_NOT_IN_LIST, resources.getString(R.string.not_in_list_group), true); onlineGroup = initGroup(Constants.VIEWGROUP_ONLINE, resources.getString(R.string.online_group), true); chatsGroup = initGroup(Constants.VIEWGROUP_CHATS, resources.getString(R.string.chats_group), true); noGroup = initGroup(Constants.VIEWGROUP_NOGROUP, resources.getString(R.string.no_group), true); } private static final ContactListAdapter initAdapter(Class<? extends ContactListAdapter> adapterClass, ProtocolResources protocolResources, List<ContactListModelGroup> contactListGroups) { try { Constructor<? extends ContactListAdapter> constructor = adapterClass.getConstructor(List.class, ProtocolResources.class); return constructor.newInstance(contactListGroups, protocolResources); } catch (Exception e) { Logger.log(e); } return null; } private final ContactListModelGroup initGroup(String groupId, String name, boolean predefined) { ContactListModelGroup g = new ContactListModelGroup(groupId, null, mServiceId, predefined); g.setName(name); return g; } private final ContactListModelGroup initGroup(BuddyGroup origin) { ContactListModelGroup g = initGroup(origin.getId(), origin.getName(), false); g.setCollapsed(origin.isCollapsed()); return g; } public void onContactListUpdated(Account account, MainActivity activity) { SharedPreferences p = activity.getSharedPreferences(account.getAccountId(), 0); showGroups = p.getBoolean(AccountOptionKeys.SHOW_GROUPS.name(), Boolean.parseBoolean(activity.getString(R.string.default_show_groups))); showOffline = p.getBoolean(AccountOptionKeys.SHOW_OFFLINE.name(), Boolean.parseBoolean(activity.getString(R.string.default_show_offline))); synchronized (mContactListGroups) { mContactListGroups.clear(); unreadGroup.getBuddyList().clear(); offlineGroup.getBuddyList().clear(); notInListGroup.getBuddyList().clear(); onlineGroup.getBuddyList().clear(); chatsGroup.getBuddyList().clear(); noGroup.getBuddyList().clear(); List<Buddy> noGroupBuddies = account.getNoGroupBuddies(); synchronized (noGroupBuddies) { for (Buddy buddy : noGroupBuddies) { BuddyGroup targetGroup = getTargetGroup(buddy, null); if (targetGroup != null) { targetGroup.getBuddyList().add(buddy); } } } List<BuddyGroup> groups = account.getBuddyGroupList(); synchronized (groups) { for (BuddyGroup origin : groups) { ContactListModelGroup viewGroup; if (showGroups && !origin.getId().equals(ApiConstants.NO_GROUP_ID)) { viewGroup = initGroup(origin); } else { viewGroup = null; } for (Buddy buddy : origin.getBuddyList()) { BuddyGroup targetGroup = getTargetGroup(buddy, viewGroup); if (targetGroup != null) { targetGroup.getBuddyList().add(buddy); } } if (viewGroup != null) { mContactListGroups.add(viewGroup); } } } if (!showGroups) { mContactListGroups.add(onlineGroup); } showPredefinedGroups(); if (!showGroups && showOffline) { mContactListGroups.add(offlineGroup); } for (BuddyGroup group : mContactListGroups) { Collections.sort(group.getBuddyList()); } mAdapter.notifyDataSetChanged(); } } private void showPredefinedGroups() { if (unreadGroup.getBuddyList().size() > 0) { mContactListGroups.add(0, unreadGroup); } if (showOffline && mContactListGroups.size() > 0) { int offlineGroupId = 0; for (;offlineGroupId < mContactListGroups.size(); offlineGroupId++) { ContactListModelGroup g = mContactListGroups.get(offlineGroupId); if (g == offlineGroup){ break; } } if (chatsGroup.getBuddyList().size() > 0) { mContactListGroups.add(offlineGroupId, chatsGroup); } if (noGroup.getBuddyList().size() > 0) { mContactListGroups.add(offlineGroupId, noGroup); } } else { if (chatsGroup.getBuddyList().size() > 0) { mContactListGroups.add(chatsGroup); } if (noGroup.getBuddyList().size() > 0) { mContactListGroups.add(noGroup); } } if (notInListGroup.getBuddyList().size() > 0) { mContactListGroups.add(notInListGroup); } } private BuddyGroup getTargetGroup(Buddy buddy, BuddyGroup idGroup) { if (buddy.getUnread() > 0) { return unreadGroup; } else if (buddy instanceof MultiChatRoom) { return chatsGroup; } else if (buddy.getGroupId() != null && buddy.getGroupId().equals(ApiConstants.NOT_IN_LIST_GROUP_ID)) { return notInListGroup; } else { if (showGroups) { if (buddy.getGroupId() == null || buddy.getGroupId().equals(ApiConstants.NO_GROUP_ID)) { return noGroup; } else if (showOffline || buddy.getOnlineInfo().getFeatures().getByte(ApiConstants.FEATURE_STATUS, (byte) -1) > -1) { return idGroup; } else { return null; } } else { if (buddy.getOnlineInfo().getFeatures().getByte(ApiConstants.FEATURE_STATUS, (byte) -1) < 0){ return offlineGroup; } else { return onlineGroup; } } } } public void onBuddyStateChanged(List<Buddy> buddies) { if (buddies == null || buddies.size() < 1) return; synchronized (mContactListGroups) { for (final Buddy buddy : buddies) { // We may need the actual protocol group for a view with "show groups", // so create a spare group link for it BuddyGroup idGroup = null; for (BuddyGroup viewGroup : mContactListGroups) { Buddy old = KindaLinq.from(viewGroup.getBuddyList()).where(new BuddyLinqRule(buddy)).first(); if (old != null) { viewGroup.getBuddyList().remove(old); if (showGroups && buddy.getGroupId().equals(viewGroup.getId())) { idGroup = viewGroup; } } } if (showGroups && idGroup == null) { idGroup = KindaLinq.from(mContactListGroups).where(new KindaLinqRule<ContactListModelGroup>() { @Override public boolean match(ContactListModelGroup t) { return t.getId().equals(buddy.getGroupId()); } }).first(); } BuddyGroup target = getTargetGroup(buddy, idGroup); if (target != null) { target.getBuddyList().add(buddy); Collections.sort(target.getBuddyList()); } } } if (canStartRedraw) { canStartRedraw = false; mContactListGroups.remove(unreadGroup); mContactListGroups.remove(notInListGroup); mContactListGroups.remove(chatsGroup); mContactListGroups.remove(noGroup); showPredefinedGroups(); mAdapter.notifyDataSetChanged(); canStartRedraw = true; } } public ContactListAdapter getAdapter() { return mAdapter; } public void onBuddyIcon(byte serviceId, String protocolUid) { //mAdapter.notifyDataSetChanged(); } public static class ContactListModelGroup extends BuddyGroup { private final boolean predefined; private ContactListModelGroup(String id, String accountId, Byte serviceId, boolean predefined) { super(id, accountId, serviceId); this.predefined = predefined; } /** * @return the predefined */ public boolean isPredefined() { return predefined; } } }